package dir.simulation;

import java.util.Vector;

import dht.data.Access;
import dht.data.AccessType;
import dht.data.Message;
import dht.data.MessageType;
import dht.simulation.DhtException;
import dht.simulation.GlobalVariables;
import dht.statistics.DhtStatistics;

public class DirDataNode {

	public int id;
	public int masterId;
	public double idleTime;
	public static final double diskTime = GlobalVariables.diskTime;

	public DirDataNode(int id, int masterId) {
		this.id = id;
		this.masterId = id;
		this.idleTime = 0.0;
	}

	public Message clientStartAccess(Access access) throws DhtException {
		Message msg = new Message();
		msg.accessId = access.accessId;
		msg.fromId = access.requesterId;
		msg.toId = masterId;
		msg.generateTime = access.startTime;
		if (access.accessType == AccessType.READ) {
			msg.msgType = MessageType.DIR_META_READ_REQ;
		} else if (access.accessType == AccessType.WRITE) {
			msg.msgType = MessageType.DIR_META_WRITE_REQ;
		}

		msg.waitingCost = 0;
		msg.processCost = diskTime;
		msg.sendTime = msg.generateTime + msg.waitingCost + msg.processCost;

		switch (msg.msgType) {
		case DIR_META_READ_REQ:
			msg.msgSize = GlobalVariables.readReqSize;
			break;
		case DIR_META_WRITE_REQ:
			msg.msgSize = GlobalVariables.writeReqSize;
			break;
		default:
			throw new DhtException("clientStartAccess msgType unknown");
		}
		return msg;
	}

	public Vector<Message> serverProcessMsg(Message msg, Access access)
			throws DhtException {
		DhtStatistics.serverCpuReport(id,
				Math.max(idleTime, msg.getCurrentTime()) - idleTime, diskTime,
				Math.max(idleTime, msg.getCurrentTime()) + diskTime);

		if (msg.msgType == MessageType.DIR_DATA_READ_ACK
				|| msg.msgType == MessageType.DIR_DATA_WRITE_ACK) {
			idleTime = Math.max(idleTime, msg.getCurrentTime()) + diskTime;
			return null;
		}
		Vector<Message> msgList = new Vector<Message>();
		Message newMsg = new Message();

		newMsg.accessId = msg.accessId;
		newMsg.fromId = msg.toId;
		newMsg.toId = msg.fromId;
		newMsg.generateTime = msg.getCurrentTime();

		idleTime = Math.max(idleTime, newMsg.generateTime);
		newMsg.waitingCost = idleTime - newMsg.generateTime;
		newMsg.processCost = diskTime;
		newMsg.sendTime = newMsg.generateTime + newMsg.waitingCost
				+ newMsg.processCost;
		idleTime = newMsg.sendTime;

		switch (msg.msgType) {
		case DIR_DATA_READ_REQ:
			DhtStatistics.serverReport(id, 0, 0, 1, 0);
			newMsg.msgSize = GlobalVariables.readRespSize + access.fileSize;
			newMsg.msgType = MessageType.DIR_DATA_READ_RESP;
			break;
		case DIR_DATA_WRITE_REQ:
			DhtStatistics.serverReport(id, 0, 0, 0, 1);
			newMsg.msgSize = GlobalVariables.writeRespSize;
			newMsg.msgType = MessageType.DIR_DATA_WRITE_RESP;
			break;
		case DIR_DATA_READ_ACK:
			break;
		case DIR_DATA_WRITE_ACK:
			break;
		default:
			throw new DhtException("serverProcessMsg msgType unknown");
		}

		msgList.add(newMsg);
		return msgList;
	}

	public Vector<Message> clientProcessMsg(Message msg, Access access)
			throws DhtException {
		Vector<Message> msgList = new Vector<Message>();
		Message newMsg = new Message();

		newMsg.accessId = msg.accessId;
		newMsg.fromId = msg.toId;
		newMsg.toId = msg.fromId;
		newMsg.generateTime = msg.getCurrentTime();

		newMsg.waitingCost = 0;
		newMsg.processCost = diskTime;
		newMsg.sendTime = newMsg.generateTime + newMsg.waitingCost
				+ newMsg.processCost;
		Message fwdAckMsg;
		switch (msg.msgType) {
		case DIR_META_READ_RESP:
			fwdAckMsg = (Message) newMsg.clone();
			fwdAckMsg.msgSize = GlobalVariables.readFwdAckSize;
			fwdAckMsg.msgType = MessageType.DIR_META_READ_ACK;
			fwdAckMsg.waitingCost = newMsg.processCost;
			fwdAckMsg.processCost = diskTime;
			fwdAckMsg.sendTime = fwdAckMsg.generateTime + fwdAckMsg.waitingCost
					+ fwdAckMsg.processCost;
			msgList.add(fwdAckMsg);

			newMsg.msgSize = GlobalVariables.readReqSize;
			newMsg.msgType = MessageType.DIR_DATA_READ_REQ;
			newMsg.toId = msg.fwdToId;
			break;
		case DIR_META_WRITE_RESP:
			fwdAckMsg = (Message) newMsg.clone();
			fwdAckMsg.msgSize = GlobalVariables.writeFwdAckSize;
			fwdAckMsg.msgType = MessageType.DIR_META_WRITE_ACK;
			fwdAckMsg.waitingCost = newMsg.processCost;
			fwdAckMsg.processCost = diskTime;
			fwdAckMsg.sendTime = fwdAckMsg.generateTime + fwdAckMsg.waitingCost
					+ fwdAckMsg.processCost;
			msgList.add(fwdAckMsg);

			newMsg.msgSize = GlobalVariables.writeReqSize + access.fileSize;
			newMsg.msgType = MessageType.DIR_DATA_WRITE_REQ;
			newMsg.toId = msg.fwdToId;
			break;
		case DIR_DATA_READ_RESP:
			newMsg.msgSize = GlobalVariables.readAckSize;
			newMsg.msgType = MessageType.DIR_DATA_READ_ACK;
			break;
		case DIR_DATA_WRITE_RESP:
			newMsg.msgSize = GlobalVariables.writeAckSize;
			newMsg.msgType = MessageType.DIR_DATA_WRITE_ACK;
			break;
		default:
			throw new DhtException("clientProcessMsg msgType unknown");
		}
		msgList.add(newMsg);
		return msgList;
	}

}